home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Libris Britannia 4
/
science library(b).zip
/
science library(b)
/
DDJMAG
/
DDJ9203.ZIP
/
386BSD.392
next >
Wrap
Text File
|
1992-01-24
|
8KB
|
237 lines
_PORTING UNIX TO THE 386: DEVICE DRIVERS_
by William Jolitz and Lynne Jolitz
[LISTING ONE]
/* [Excerpted from /sys/i386/isa/icu.h] */
...
/* Interrupt enable bits -- in order of priority */
#define IRQ0 0x0001 /* highest priority - timer */
#define IRQ1 0x0002
#define IRQ_SLAVE 0x0004
#define IRQ8 0x0100
#define IRQ9 0x0200
#define IRQ2 IRQ9
#define IRQ10 0x0400
#define IRQ11 0x0800
#define IRQ12 0x1000
#define IRQ13 0x2000
#define IRQ14 0x4000
#define IRQ15 0x8000
#define IRQ3 0x0008
#define IRQ4 0x0010
#define IRQ5 0x0020
#define IRQ6 0x0040
#define IRQ7 0x0080 /* lowest - parallel printer */
...
[LISTING TWO]
/* [Excerpted from /sys/i386/isa/icu.h] */
...
/* Interrupt "level" mechanism variables, masks, and macros */
#define INTREN(s) __nonemask__ &= ~(s)
#define INTRDIS(s) __nonemask__ |= (s)
#define INTRMASK(msk,s) msk |= (s)
...
/* [Excerpted from /sys/i386/isa/isa.c] */
...
/* Configure all ISA devices */
isa_configure() {
struct isa_device *dvp;
struct isa_driver *dp;
splhigh();
INTREN(IRQ_SLAVE);
/* configure devices, constructing group masks as we go */
for (dvp = isa_devtab_bio; config_isadev(dvp,&__biomask__); dvp++);
for (dvp = isa_devtab_tty; config_isadev(dvp,&__ttymask__); dvp++);
for (dvp = isa_devtab_net; config_isadev(dvp,&__netmask__); dvp++);
for (dvp = isa_devtab_null; config_isadev(dvp,0); dvp++);
/* if we support slip, then any tty interrupt is a potential net intr */
#include "sl.h"
#if NSL > 0
__netmask__ |= __ttymask__;
__ttymask__ |= __netmask__;
#endif
/* if not enabled, don't allow in ANY mask to become enabled */
__biomask__ |= __nonemask__;
__ttymask__ |= __nonemask__;
__netmask__ |= __nonemask__;
__protomask__ |= __nonemask__;
splnone();
}
/* Configure an ISA device. */
config_isadev(isdp, mp)
struct isa_device *isdp;
int *mp;
{
struct isa_driver *dp;
if (dp = isdp->id_driver) {
/* does this device have any I/O shared memory? */
if (isdp->id_maddr) {
extern int atdevbase[];
/* convert from PC absolute physical to virtual */
isdp->id_maddr -= IOM_BEGIN;
isdp->id_maddr += (int)&atdevbase;
}
/* "Is there anyone on board?" -- Star Trek */
isdp->id_alive = (*dp->probe)(isdp);
if (isdp->id_alive) {
printf("%s%d", dp->name, isdp->id_unit);
(*dp->attach)(isdp);
printf(" at 0x%x ", isdp->id_iobase);
/* have we got an interrupt to wire down? */
if(isdp->id_irq) {
int intrno;
intrno = ffs(isdp->id_irq)-1;
printf("irq %d ", intrno);
INTREN(isdp->id_irq);
/* add to a group mask?? */
if(mp)INTRMASK(*mp,isdp->id_irq);
/* wire interrupt */
setidt(ICU_OFFSET+intrno, isdp->id_intr,
SDT_SYS386IGT, SEL_KPL);
}
/* perhaps a DMA channel request as well? */
if (isdp->id_drq != -1) printf("drq %d ", isdp->id_drq);
printf("on isa\n");
}
return (1);
} else return(0);
}
...
[LISTING THREE
/* [Excerpted from /sys/i386/include/param.h] */
...
#ifndef __ORPL__
/* Interrupt Group Masks */
extern u_short __highmask__; /* interrupts masked with splhigh() */
extern u_short __ttymask__; /* interrupts masked with spltty() */
extern u_short __biomask__; /* interrupts masked with splbio() */
extern u_short __netmask__; /* interrupts masked with splimp() */
extern u_short __protomask__; /* interrupts masked with splnet() */
extern u_short __nonemask__; /* interrupts masked with splnone() */
asm(" .set IO_ICU1, 0x20 ; .set IO_ICU2, 0xa0 ");
/* adjust priority level to disable a group of interrupts */
#define __ORPL__(m) ({ u_short oldpl, msk; \
msk = (msk); \
asm volatile (" \
cli ; /* modify interrupts atomically */ \
movw %1, %%dx ; /* get mask to OR in */ \
inb $ IO_ICU1+1, %%al ; /* get low order mask */ \
xchgb %%dl, %%al ; /* switch the old with the new */ \
orb %%dl, %%al ; /* finally, OR both it in! */ \
outb %%al, $ IO_ICU1+1 ; /* and stuff it back where it came */ \
inb $ 0x84, %%al ; /* post it & handle write recovery */ \
inb $ IO_ICU2+1, %%al ; /* next, get high order mask */ \
xchgb %%dh, %%al ; /* switch the old with the new */ \
orb %%dh, %%al ; /* finally, or it in! */ \
outb %%al, $ IO_ICU2+1 ; /* and stuff it back where it came */ \
inb $ 0x84, %%al ; /* post it & handle write recovery */ \
movw %%dx, %0 ; /* return old mask */ \
sti /* allow interrupts again */ " \
: "&=g" (oldpl) /* return values */ \
: "g" ((m)) /* arguments */ \
: "ax", "dx" /* registers used */ \
); \
oldpl; /* return the "old" value */ \
})
/* force priority mask to a set value */
#define __SETPL__(m) ({ u_short oldpl, msk; \
msk = (msk); \
asm volatile (" \
cli ; /* modify interrupts atomically */ \
movw %1, %%dx ; /* get mask to OR in */ \
inb $ IO_ICU1+1, %%al ; /* get low order mask */ \
xchgb %%dl, %%al ; /* switch the old with the new */ \
outb %%al, $ IO_ICU1+1 ; /* and stuff it back where it came */ \
inb $ 0x84, %%al ; /* post it & handle write recovery */ \
inb $ IO_ICU2+1, %%al ; /* next, get high order mask */ \
xchgb %%dh, %%al ; /* switch the old with the new */ \
outb %%al, $ IO_ICU2+1 ; /* and stuff it back where it came */ \
inb $ 0x84, %%al ; /* post it & handle write recovery */ \
movw %%dx, %0 ; /* return old mask */ \
sti /* allow interrupts again */ " \
: "&=g" (oldpl) /* return values */ \
: "g" ((m)) /* arguments */ \
: "ax", "dx" /* registers used */ \
); \
oldpl; /* return the "old" value */ \
})
#define splhigh() __ORPL__(__highmask__)
#define spltty() __ORPL__(__ttymask__)
#define splbio() __ORPL__(__biomask__)
#define splimp() __ORPL__(__netmask__)
#define splnet() __ORPL__(__protomask__)
#define splsoftclock() __ORPL__(__protomask__)
#define splx(v) ({ u_short val; \
val = (v); \
if (val == __nonemask__) (void) spl0(); /* zero is special */ \
else (void) __SETPL__(val); \
})
#endif __ORPL__
...
[LISTING FOUR]
/* [Excerpted from /sys/i386/i386/machdep.c] */
...
/* Fill out a gate descriptor uses as an interrupt vector. */
setidt(idx, func, typ, dpl) char *func; {
struct gate_descriptor *ip = idt + idx;
ip->gd_looffset = (int)func;
ip->gd_selector = GSEL(GCODE_SEL,SEL_KPL);
ip->gd_stkcpy = 0;
ip->gd_xx = 0;
ip->gd_type = typ;
ip->gd_dpl = dpl; /* can we allow INT's to this IDT index? */
ip->gd_p = 1; /* yup, we're here, don't segment fault me */
ip->gd_hioffset = ((int)func)>>16 ;
}
...
[LISTING FIVE]
/* [Excerpted from /sys/i386/include/segments.h] */
...
/* Gate descriptors (e.g. indirect descriptors)
* [The IDT is made up of these as well.] */
struct gate_descriptor {
unsigned gd_looffset:16 ; /* gate offset (lsb) */
unsigned gd_selector:16 ; /* gate segment selector */
unsigned gd_stkcpy:5 ; /* number of stack wds to cpy */
unsigned gd_xx:3 ; /* unused */
unsigned gd_type:5 ; /* segment type */
unsigned gd_dpl:2 ; /* segment descriptor priority level */
unsigned gd_p:1 ; /* segment descriptor present */
unsigned gd_hioffset:16 ; /* gate offset (msb) */
} ;
...